// 导入必要的 React 核心功能
import React, { useState, useEffect, useCallback, useRef } from 'react'
// 导入 Ant Design Mobile 的卡片组件，用于展示健康资讯列表
import { Card } from 'antd-mobile'
// 导入 react-window 的虚拟列表组件，用于优化大量数据的渲染性能
import { FixedSizeList as List } from 'react-window'
// 导入 React Router 的导航钩子，用于页面跳转
import { useNavigate } from 'react-router-dom'
// 导入自定义的请求工具，用于与后端 API 通信
import request from '../api/request'

/**
 * 健康资讯数据项的接口定义
 * 定义了每个健康资讯文章的数据结构
 */
interface InformationItem {
  id: number;           // 资讯的唯一标识符
  title: string;        // 资讯标题
  thumbnail: string;    // 资讯缩略图URL
  source: string;       // 资讯来源（如：健康时报、医学网等）
  releaseTime: number;  // 发布时间戳（毫秒）
}

/**
 * 健康资讯列表组件的属性接口
 * 定义了组件可以接收的外部属性
 */
interface HealthInformationListProps {
  className?: string;                    // 可选的CSS类名，用于自定义样式
  style?: React.CSSProperties;          // 可选的CSS样式对象，用于内联样式
}

/**
 * 健康资讯列表组件
 * 功能：
 * 1. 展示健康资讯列表
 * 2. 使用虚拟滚动优化性能
 * 3. 支持无限滚动加载
 * 4. 自动轮播显示
 * 5. 点击跳转到详情页
 */
const HealthInformationList: React.FC<HealthInformationListProps> = ({ className, style }) => {
  // 获取路由导航函数，用于页面跳转
  const navigate = useNavigate()

  // ==================== 状态管理 ====================
  
  /**
   * 存储所有健康资讯数据的数组
   * 包含从API获取的所有资讯信息
   */
  const [allInformationData, setAllInformationData] = useState<InformationItem[]>([])
  
  /**
   * 标记是否还有更多数据可以加载
   * true: 还有更多数据，false: 已加载完所有数据
   */
  const [hasMore, setHasMore] = useState(true)

  /**
   * 标记当前是否正在加载数据
   * 用于防止重复请求和显示加载状态
   */
  const [isLoading, setIsLoading] = useState(false)

  // ==================== 虚拟列表配置常量 ====================

  /**
   * 每个资讯项的高度（包含间距）
   * 这个值需要与CSS中的实际高度保持一致
   */
  const ITEM_HEIGHT = 84

  /**
   * 默认可见的资讯项数量
   * 决定了容器的初始高度
   */
  const VISIBLE_ITEMS = 5

  /**
   * 虚拟列表容器的总高度
   * 计算公式：单个项目高度 × 可见项目数量
   */
  const CONTAINER_HEIGHT = ITEM_HEIGHT * VISIBLE_ITEMS

  // ==================== 容器可视性监听相关 ====================

  /**
   * 健康资讯容器的DOM引用
   * 用于监听容器是否在视口中可见
   */
  const informationContainerRef = useRef<HTMLDivElement>(null)

  /**
   * 标记健康资讯容器是否在视口中可见
   * 用于控制自动轮播功能
   */
  const [isInformationVisible, setIsInformationVisible] = useState(false)

  /**
   * 格式化时间戳为相对时间
   * 将毫秒时间戳转换为"X天前"、"X小时前"、"X分钟前"等易读格式
   * 
   * @param timestamp - 毫秒时间戳
   * @returns 格式化后的相对时间字符串
   */
  const formatTime = (timestamp: number) => {
    // 获取当前时间戳
    const now = new Date().getTime()
    // 计算时间差（毫秒）
    const diff = now - timestamp

    // 计算天数差
    const days = Math.floor(diff / (1000 * 60 * 60 * 24))
    // 计算小时差
    const hours = Math.floor(diff / (1000 * 60 * 60))
    // 计算分钟差
    const minutes = Math.floor(diff / (1000 * 60))

    // 根据时间差返回相应的格式化字符串
    if (days > 0) {
      return `${days}天前`
    } else if (hours > 0) {
      return `${hours}小时前`
    } else if (minutes > 0) {
      return `${minutes}分钟前`
    } else {
      return '刚刚'
    }
  }

  /**
   * 设置 Intersection Observer 监听健康资讯容器的可视性
   * 当容器进入或离开视口时，更新 isInformationVisible 状态
   * 这个监听器用于控制自动轮播功能
   */
  useEffect(() => {
    // 确保容器DOM元素存在
    if (informationContainerRef.current) {
      // 创建 Intersection Observer 实例
      // IntersectionObserver 是浏览器提供的 API，用于异步观察目标元素与祖先元素
      // 或视口（viewport）的交集变化情况，常用来实现懒加载（如图片进入视口再加载）、
      // 滚动动画触发、元素可见性检测等功能 ，回调函数会在观察的元素进入或离开视口
      // （或指定根元素）时执行。 示例中new IntersectionObserver后一般要传入回调函
      // 数等参数来完成实例配置 
      const observer = new IntersectionObserver(
        // 回调函数，当观察的元素进入或离开视口时触发
        // ([entry]) => {...}：当观察的 DOM 进入 / 离开视口时，会触发这个回调。
        // entry.isIntersecting 是布尔值，true 表示「进入视口」，false 表示「离开视口」
        ([entry]) => {
          // 更新容器的可见性状态
          setIsInformationVisible(entry.isIntersecting);
        },
        {
          threshold: 0.1, // 当10%的容器可见时触发回调
          rootMargin: '0px' // 根元素的边距，这里不设置额外边距
        }
      );

      // 开始观察容器元素
      // 让 IntersectionObserver 开始监听这个容器是否进入视口
      observer.observe(informationContainerRef.current);

      // 清理函数：组件卸载时停止观察
      // 组件卸载时执行 disconnect，停止监听，避免内存泄漏或无效回调
      return () => {
        observer.disconnect();
      };
    }
  }, []); // 空依赖数组，只在组件挂载时执行一次

  /**
   * 获取健康资讯数据
   * 从后端API获取健康资讯列表数据
   * 
   * @param page - 页码，默认为1
   * @param append - 是否追加数据，true为追加，false为替换
   */
  // 用于缓存函数，避免因组件重新渲染导致函数重复创建，优化性能，常和 useEffect 等配合，当依赖不变时复用函数
  const getInformationList = useCallback((page: number = 1, append: boolean = false) => {
    // 防止重复请求：如果正在加载或没有更多数据且不是追加模式，则直接返回
    if (isLoading || (!append && !hasMore)) return

    // 设置加载状态为true
    setIsLoading(true)

    // 发起API请求获取健康资讯数据
    request.get(`/health/share/information/v1/findInformationList?plateId=1&page=${page}&count=50`).then((res) => {
      // 请求成功，状态码为200
      if (res.status === 200) {
        // 从响应中提取数据，如果result不存在则使用空数组
        const newData = res.data.result || []

        // 根据append参数决定是追加还是替换数据
        if (append) {
          // 追加模式：将新数据添加到现有数据后面
          // prev => [...prev, ...newData]：这是一个函数式更新写法 
          //prev 代表状态的 “上一个值”，[...prev, ...newData] 
          // 利用 ES6 扩展运算符，把之前状态数组 prev 的内容和新数据数组 newData 的内容合并，
          // 生成新数组，达到往状态数组里追加新数据的效果 ，常用于列表数据的增量更新场景
          // （比如滚动加载更多、接口分批获取数据后合并展示）。
          // 简单说，就是在 React 组件里，用函数式更新的方式，给 allInformationData 状态数组 “拼接” 新数据，
          // 保持状态更新的准确性和不可变性
          setAllInformationData(prev => [...prev, ...newData])
        } else {
          // 替换模式：用新数据替换现有数据
          setAllInformationData(newData)
        }

        // 判断是否还有更多数据
        // 如果返回的数据少于50条，说明已经到达最后一页
        setHasMore(newData.length === 50)
      }
    }).catch((error) => {
      // 请求失败时的错误处理
      console.error('获取健康资讯失败:', error);
    }).finally(() => {
      // 无论成功还是失败，都要将加载状态设置为false
      setIsLoading(false)
    })
  }, [isLoading, hasMore]) // 依赖项：isLoading 和 hasMore

  /**
   * 点击资讯项跳转到详情页
   * 
   * @param id - 资讯的唯一标识符
   */
  const goDetail = (id: number) => {
    // 使用路由导航跳转到资讯详情页，并传递资讯ID作为查询参数
    navigate(`/information-detail?id=${id}`)
  }

  /**
   * 虚拟列表的渲染项函数
   * 这个函数会被 react-window 的 List 组件调用，用于渲染每个资讯项
   * 
   * @param index - 当前项的索引
   * @param style - react-window 提供的样式对象，包含定位信息
   * @returns 渲染的资讯项JSX元素
   */
  const renderInformationItem = useCallback(({ index, style }: { index: number; style: React.CSSProperties }) => {
    // 根据索引获取对应的资讯数据
    const item = allInformationData[index]

    // 如果数据不存在，返回null（这种情况不应该发生，但作为安全措施）
    if (!item) return null

    return (
      // 资讯项容器，点击时跳转到详情页
      <div style={style} className='information-item' onClick={() => goDetail(item.id)}>
        {/* 资讯图片容器 */}
        <div className='information-image'>
          {/* 资讯缩略图 */}
          <img
            src={item.thumbnail}
            alt={item.title}
            // 图片加载失败时的处理
            onError={(e) => {
              const target = e.target as HTMLImageElement;
              // 隐藏加载失败的图片
              target.style.display = 'none';
              // 显示占位符（移除hidden类）
              target.nextElementSibling?.classList.remove('hidden');
            }}
          />
          {/* 图片占位符，默认隐藏，图片加载失败时显示 */}
          <div className='information-placeholder hidden'>
            <span>暂无图片</span>
          </div>
        </div>

        {/* 资讯内容容器 */}
        <div className='information-content'>
          {/* 资讯标题 */}
          <h4 className='information-title-text'>{item.title}</h4>
          {/* 资讯元信息（来源和时间） */}
          <div className='information-meta'>
            <span className='information-source'>{item.source}</span>
            <span className='information-time'>{formatTime(item.releaseTime)}</span>
          </div>
        </div>
      </div>
    )
  }, [allInformationData]) // 依赖项：allInformationData

  /**
   * 组件挂载时获取初始数据
   * 这个 effect 在组件首次渲染时执行，获取第一页的健康资讯数据
   */
  useEffect(() => {
    getInformationList()
  }, [getInformationList]) // 依赖项：getInformationList 函数

  // ==================== 组件渲染 ====================
  
  return (
    // 使用 Ant Design Mobile 的 Card 组件作为容器
    <Card
      className={className}
      style={{ marginTop: '10px', marginBottom: '0', padding: '8px', ...style }}
    >
      {/* 健康资讯区域容器 */}
      <div className='information-section'>
        {/* 健康资讯头部 */}
        <div className='information-header'>
          <span className='information-title'>健康资讯</span>
          <span className='information-more'>更多 &gt;</span>
        </div>

        {/* 虚拟列表容器 */}
        <div
          ref={informationContainerRef}  // 绑定DOM引用，用于监听可视性
          className='information-virtual-list'
          style={{
            height: CONTAINER_HEIGHT,
            position: 'relative',
            width: '100%',
            maxWidth: '100%',
            boxSizing: 'border-box'
          }}
          // 添加title属性用于调试，显示容器的可视状态
          title={`健康资讯容器 - 可视状态: ${isInformationVisible ? '可见' : '不可见'}`}
        >
          {/* 条件渲染：有数据时显示虚拟列表，无数据时显示加载状态 */}
          {allInformationData.length > 0 ? (
            // 使用 react-window 的虚拟列表组件
            <List
              height={CONTAINER_HEIGHT}
              itemCount={Math.min(allInformationData.length, 12)}
              itemSize={ITEM_HEIGHT}
              width="100%"
              overscanCount={0}
              style={{ maxWidth: '100%', width: '100%', boxSizing: 'border-box' }}
              onScroll={({ scrollOffset }) => {
                // 只有在容器可见时才执行自动轮播逻辑
                if (isInformationVisible) {
                  const distanceToBottom = Math.min(allInformationData.length, 12) * ITEM_HEIGHT - (scrollOffset + CONTAINER_HEIGHT)
                  
                  if (distanceToBottom <= 0 && allInformationData.length >= 5) {
                    // 使用 setTimeout 延迟执行，确保滚动动画流畅
                    setTimeout(() => {
                      // 获取虚拟列表容器元素
                      const listElement = document.querySelector('.information-virtual-list') as HTMLDivElement | null
                      // 平滑滚动到顶部
                      listElement?.scrollTo({ top: 0, behavior: 'smooth' })
                    }, 100)
                  }
                }
              }}
            >
              {/* 渲染函数，用于渲染每个列表项 */}
              {renderInformationItem}
            </List>
          ) : (
            // 无数据时显示的加载状态
            <div className='information-loading'>
              <p>{isLoading ? '加载中...' : '暂无数据'}</p>
            </div>
          )}
        </div>

        {/* 加载更多提示，只在有数据且正在加载时显示 */}
        {isLoading && allInformationData.length > 0 && (
          <div className='information-loading-more'>
            <p>加载更多...</p>
          </div>
        )}
      </div>
    </Card>
  )
}

// 导出组件
export default HealthInformationList
